package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AuditService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.atguigu.tingshu.common.constant.SystemConstant.*;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private VodService vodService;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private AuditService auditService;
    @Qualifier("com.atguigu.tingshu.user.client.UserFeignClient")
    @Autowired
    private UserFeignClient userFeignClient;


    /**
     * 保存声音
     *
     * @param trackInfoVo
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //1.根据所属专辑ID查询专辑信息 得到封面图片，用于后续更新
        Long albumId = trackInfoVo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            log.error("专辑:{}不存在", albumId);
            throw new GuiguException(404, "专辑不存在");
        }
        //2.新增声音记录
        //2.1 将声音VO转为PO
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        //2.2 给属性赋值
        //2.2.1 设置用户ID
        trackInfo.setUserId(userId);
        //2.2.2 设置声音序号 要求从1开始递增
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        //2.2.3 调用点播平台获取音频详情信息：时长、大小、类型
        TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfo.getMediaFileId());
        if (trackMediaInfoVo != null) {
            trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        //2.2.4 来源：用户上传
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
        //2.2.5 状态：待审核
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        //2.2.6 封面图片 如果未提交使用所属专辑封面
        String coverUrl = trackInfo.getCoverUrl();
        if (StringUtils.isBlank(coverUrl)) {
            trackInfo.setCoverUrl(albumInfo.getCoverUrl());
        }
        //2.3 新增声音记录
        trackInfoMapper.insert(trackInfo);
        Long trackId = trackInfo.getId();

        //3. 更新专辑信息：包含声音数量
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);

        //4.新增声音统计记录
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);
        this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);

        //5. 内容审核-文本审核
        String content = trackInfo.getTrackTitle() + trackInfo.getTrackIntro();
        String suggestion = auditService.auditText(content);
        if ("pass".equals(suggestion)) {
            trackInfo.setStatus(ALBUM_STATUS_PASS);
        } else if ("review".equals(suggestion)) {
            trackInfo.setStatus(ALBUM_STATUS_ARTIFICIAL);
        } else if ("block".equals(suggestion)) {
            trackInfo.setStatus(ALBUM_STATUS_NO_PASS);
        }

        //6.对点播平台音频文件进行审核（异步审核）
        String reviewTaskId = auditService.startReviewTask(trackInfo.getMediaFileId());
        trackInfo.setStatus(TRACK_STATUS_REVIEWING);
        trackInfo.setReviewTaskId(reviewTaskId);
        trackInfoMapper.updateById(trackInfo);
        trackInfoMapper.updateById(trackInfo);
    }


    /**
     * 保存声音统计信息
     *
     * @param trackId  声音ID
     * @param statType 统计类型
     * @param statNum  统计数值
     */
    @Override
    public void saveTrackStat(Long trackId, String statType, int statNum) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }


    @Override
    public Page<TrackListVo> getUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.getUserTrackPage(pageInfo, trackInfoQuery);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
        //根据数据库，id查声音,并保存旧的声音id
        TrackInfo trackInfo = trackInfoMapper.selectById(id);

        //1.2 对修改后的内容进行审核
        String content = trackInfoVo.getTrackTitle() + trackInfoVo.getTrackIntro();
        String suggestion = auditService.auditText(content);
        if ("pass".equals(suggestion)) {
            trackInfo.setStatus(ALBUM_STATUS_PASS);
        } else if ("review".equals(suggestion)) {
            trackInfo.setStatus(ALBUM_STATUS_ARTIFICIAL);
        } else if ("block".equals(suggestion)) {
            trackInfo.setStatus(ALBUM_STATUS_NO_PASS);
        }


        String oldId = trackInfo.getMediaFileId();
        //判断声音是否更新，若更新，获得点播平台最新声音  再次审核变更后的音频，删除原有的声音
        if (!trackInfoVo.getMediaFileId().equals(trackInfo.getMediaFileId())) {
            //说明声音变更了，id不一致，点播平台的声音id！=数据库的声音id
            //这里的数据库id时旧id，还没有被删除，点播平台又新的唯一id
            TrackMediaInfoVo trackMediaInfo =
                    vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
            if (trackMediaInfo != null) {
                //获得最新声音信息，把值赋值给数据库
                trackInfo.setMediaFileId(trackInfoVo.getMediaFileId());
                trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
                trackInfo.setMediaType(trackMediaInfo.getType());
                trackInfo.setMediaSize(trackMediaInfo.getSize());
                trackInfo.setMediaUrl(trackMediaInfo.getMediaUrl());
                //数据库旧文件更改完毕，再次审核更新后的跟云中是否一致：审核中

                //trackInfo.setStatus("审核中");
                //3.对修改后音频文件进行内容审核:发起审核任务
                String reviewTaskId = auditService.startReviewTask(trackInfo.getMediaFileId());
                trackInfo.setStatus(TRACK_STATUS_REVIEWING);
                trackInfo.setReviewTaskId(reviewTaskId);
            }
            //删除点播平台旧文件
            vodService.deleteMedia(oldId);
        }
        //更新数据库中声音记录，
        trackInfoMapper.updateById(trackInfo);


        //1.判断音频文件是否变更
        TrackInfo oldTrackInfo = trackInfoMapper.selectById(trackInfo.getId());
        //1.2 判断文件是否被更新
        if (!trackInfo.getMediaFileId().equals(oldTrackInfo.getMediaFileId())) {
            //1.3 如果文件被更新，再次获取新音频文件信息更新：时长，大小，类型，如果更新，调用点播平台获取最新信息， 并审核，删除原有的
            TrackMediaInfoVo mediaInfoVo = vodService.getTrackMediaInfo(trackInfo.getMediaFileId());
            if (mediaInfoVo != null) {
                trackInfo.setMediaType(mediaInfoVo.getType());//格式
                trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfoVo.getDuration()));//时长
                trackInfo.setMediaSize(mediaInfoVo.getSize());//大小
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);//状态
                //1.4 从点播平台删除旧的音频文件
                vodService.deleteMedia(oldTrackInfo.getMediaFileId());
            }
            //2.更新声音信息
            trackInfoMapper.updateById(trackInfo);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        Long albumId = trackInfo.getAlbumId();//专辑id
        Integer orderNum = trackInfo.getOrderNum();//声音在专辑中的排序值
        //2.更新声音表序号
        //更新之前再次判断是否一致，防止我们获取信息之后又更新了
        LambdaUpdateWrapper<TrackInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TrackInfo::getAlbumId, albumId);
        updateWrapper.gt(TrackInfo::getOrderNum, orderNum);

        //2.2 修改字段值
        updateWrapper.setSql("order_num = order_num - 1");
        trackInfoMapper.update(null, updateWrapper);

        //3.删除声音表记录
        trackInfoMapper.deleteById(id);

        //4.删除声音统计
        LambdaQueryWrapper<TrackStat> trackStatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        trackStatLambdaQueryWrapper.eq(TrackStat::getTrackId, id);
        trackStatMapper.delete(trackStatLambdaQueryWrapper);

        //5.更新专辑包含声音数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);


        //6.删除点播平台音频文件
        vodService.deleteMedia(trackInfo.getMediaFileId());
    }


    /**
     * 需求：用户未登录，可以给用户展示声音列表；
     * 用户已登录，可以给用户展示声音列表，并动态渲染付费标识
     * 分页查询专辑下声音列表（动态渲染付费标识）
     *
     * @param pageInfo MP分页对象
     * @param albumId  专辑ID
     * @param userId   用户ID
     * @return
     */
    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(
            IPage<AlbumTrackListVo> pageInfo,
            Long albumId,
            Long userId) {
        //1.分页获取声音列表
        pageInfo = trackInfoMapper.findAlbumTrackPage(pageInfo, albumId);
        //2.动态渲染付费标识
        //查询专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Assert.notNull(albumInfo, "专辑{}不存在", albumId);
        //专辑付费类型：0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        //免费集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        //3.判断是否登录
        //未登录
        if (userId == null) {
            //vip免费或者需要付费，声音需要付费才能听
            if (ALBUM_PAY_TYPE_VIPFREE.equals(payType) || ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                pageInfo.getRecords().stream().filter(track -> track.getOrderNum() > tracksForFree)
                        .forEach(track -> track.setIsShowPaidMark(true));
            }
        } else {
            //登录
            //是否为会员，获取用户信息查看会员是否过期
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo, "用户{}不存在", userId);
            boolean isVIP = false;
            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                isVIP = true;
            }
            // 情况二：如果专辑 付费类型：VIP免费 且 当前用户是普通用户，满足进一步查询当前页声音购买状态
            //vip免费但你不是vip,那就检查你是否购买这个声音
            Boolean isNeedCheckPayStatus = false;
            if (!isVIP && ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
                isNeedCheckPayStatus = true;
            }
            //情况三：如果专辑 付费类型：付费，无论什么用户，满足进一步查询当前页声音购买状态
            //付费的情况下都需要检查付费状态
            if (ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                isNeedCheckPayStatus = true;
            }
            //4.4 如果满足情况二或情况三，远程调用用户服务，得到当前页除试听部分每个声音购买状态
            if (isNeedCheckPayStatus) {//需要检查
                //4.4.1 获取当前页中除试听以外其他声音ID列表
                List<Long> list = pageInfo.getRecords().stream()
                        .filter(t -> t.getOrderNum() > tracksForFree).map(AlbumTrackListVo::getTrackId)
                        .collect(Collectors.toList());
                //远程调用用户服务，获取当前页中声音购买状态Map<Long-专辑ID,Integer-购买状态>
                //远程调用
                Map<Long, Integer> payStatusMap = userFeignClient.userIsPaidTrack(userId, albumId, list).getData();
                //根据声音是否需要购买状态状态修改付费标识
                pageInfo.getRecords().stream()
                        .filter(t -> t.getOrderNum() > tracksForFree)
                        .forEach(t -> t.setIsShowPaidMark(payStatusMap.get(t.getTrackId()) == 0));
            }
        }
        return pageInfo;
    }

    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackStat(TrackStatMqVo mqVo) {
        /*
        * 从vo中获取消息改变数据库
        * */
        //1.更新声音统计数值
        trackStatMapper.update(null,
                new LambdaUpdateWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, mqVo.getTrackId())
                        .eq(TrackStat::getStatType, mqVo.getStatType())
                        .setSql("stat_num = stat_num + " + mqVo.getCount())
        );
        //2.如果是"播放"or"评论"还需要更新专辑统计数值
        if (TRACK_STAT_PLAY.equals(mqVo.getStatType())) {
            //更新专辑统计表播放量
            albumStatMapper.update(
                    null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, mqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, ALBUM_STAT_PLAY)
                            .setSql("stat_num = stat_num + " + mqVo.getCount())
            );
        }
        if (TRACK_STAT_COMMENT.equals(mqVo.getStatType())) {
            //更新专辑统计表评论量
            albumStatMapper.update(
                    null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, mqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, ALBUM_STAT_COMMENT)
                            .setSql("stat_num = stat_num + " + mqVo.getCount())
            );
        }
    }

    /**
     * 查询声音统计信息
     * @param trackId
     * @return
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackInfoMapper.getTrackStatVo(trackId);
    }
}
